﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Xml;
using HalconDotNet;
using Go;

namespace fhs
{
    abstract class VisionBase
    {
        static protected HDevelopExport hv = new HDevelopExport();
        static protected shared_strand _execStrand = new shared_strand();
        static public work_engine saveWork = functional.init(delegate ()
        {
            work_engine eng = new work_engine();
            eng.run(background: true);
            return eng;
        });
        static public work_engine genWork = functional.init(delegate ()
        {
            int threads = DefaultLoad.Load(1, "./Config/GenThreads.txt", 0);
            work_engine eng = new work_engine();
            eng.run(threads, background: true);
            return eng;
        });

        protected class ViewObjects
        {
            public LinkedList<ObjectShow> drawObjects = new LinkedList<ObjectShow>();
            public LinkedList<WindowTexts> drawTexts = new LinkedList<WindowTexts>();
            public CameraControl[] views = null;
        }

        private DateTime _productTime = DateTime.Now;
        protected generator.local<ViewObjects> viewObjects = new generator.local<ViewObjects>();

        abstract public class ParamBase
        {
            public abstract VisionName.Vision Name { get; }
            public abstract void Load(string productName);
            public abstract void Save(string productName);

            protected string CommonPath
            {
                get
                {
                    return $@".\VisionConfig\Common\{Name}";
                }
            }

            protected string ProductPath(string productName)
            {
                return $@".\VisionConfig\Product\{ProductMgr.currProduct}\{Name}";
            }
        }

        abstract public class OptionBase
        {
        }

        abstract public class ResultBase
        {
        }

        public abstract VisionName.Vision Name { get; }

        public DateTime ProductTime
        {
            set
            {
                _productTime = value;
            }
        }

        protected async Task ClearViews()
        {
            System.Diagnostics.Debug.Assert(null != viewObjects.value);
            generator.lock_shield();
            if (null != viewObjects.value.views)
            {
                foreach (CameraControl view in viewObjects.value.views)
                {
                    view.Reset();
                    await generator.yield();
                }
            }
            await generator.unlock_shield();
        }

        private async Task RefViews(CameraControl mainView)
        {
            generator.lock_shield();
            mainView.Text = mainView.Title;
            mainView.SetObjects(viewObjects.value.drawObjects);
            mainView.SetTexts(viewObjects.value.drawTexts);
            mainView.ShowImage();
            if (null != viewObjects.value.views)
            {
                int idx = 0;
                foreach (ObjectShow obj in viewObjects.value.drawObjects)
                {
                    viewObjects.value.views[idx].SetSize(mainView.GetSize().Width, mainView.GetSize().Height);
                    viewObjects.value.views[idx].MainColor = obj.color;
                    viewObjects.value.views[idx].Margin = obj.margin;
                    viewObjects.value.views[idx].Text = obj.text;
                    viewObjects.value.views[idx].ShowImage(obj.obj);
                    await generator.yield();
                    if (++idx == viewObjects.value.views.Length)
                    {
                        LogMgr.Error("绘制对象数量太多");
                        break;
                    }
                }
                for (; idx < viewObjects.value.views.Length; idx++)
                {
                    viewObjects.value.views[idx].Reset();
                    await generator.yield();
                }
            }
            await generator.unlock_shield();
        }

        protected abstract Task<ResultBase> Translate(bool isPreview, CameraControl mainView, ParamBase param = null, OptionBase option = null);
        protected abstract Task<ResultBase> RefPriview(CameraControl mainView, HObject[] images, ParamBase param = null);

        public async Task<ResultBase> Translate(CameraControl mainView, CameraControl[] views, ParamBase param = null, OptionBase option = null)
        {
            try
            {
                viewObjects.value = new ViewObjects { views = views };
                await ClearViews();
                mainView.Text = mainView.Title;
                ResultBase res = await Translate(false, mainView, param, option);
                await RefViews(mainView);
                return res;
            }
            catch (generator.stop_exception)
            {
                throw;
            }
            catch (Exception ec)
            {
                LogMgr.Error($"{Name}视觉错误");
                if (null == ec.Source)
                {
                    LogMgr.File($"{Name}视觉错误:{ec.Message}\r\n{ec.StackTrace}");
                }
                else
                {
                    LogMgr.File($"{Name}视觉错误:{ec.Message}\r\n{ec.Source}\r\n{ec.StackTrace}");
                }
                return null;
            }
        }

        public async Task<ResultBase> Preview(CameraControl mainView, CameraControl[] views, ParamBase param = null, OptionBase option = null)
        {
            try
            {
                viewObjects.value = new ViewObjects { views = views };
                await ClearViews();
                mainView.Text = mainView.Title;
                ResultBase res = await Translate(true, mainView, param, option);
                await RefViews(mainView);
                return res;
            }
            catch (generator.stop_exception)
            {
                throw;
            }
            catch (Exception ec)
            {
                LogMgr.Error($"{Name}视觉错误");
                if (null == ec.Source)
                {
                    LogMgr.File($"{Name}视觉错误:{ec.Message}\r\n{ec.StackTrace}");
                }
                else
                {
                    LogMgr.File($"{Name}视觉错误:{ec.Message}\r\n{ec.Source}\r\n{ec.StackTrace}");
                }
                return null;
            }
        }

        public async Task<ResultBase> RefPriview(CameraControl mainView, CameraControl[] views, HObject[] images, ParamBase param = null)
        {
            try
            {
                viewObjects.value = new ViewObjects { views = views };
                await ClearViews();
                mainView.Text = mainView.Title;
                ResultBase res = await RefPriview(mainView, images, param);
                await RefViews(mainView);
                return res;
            }
            catch (generator.stop_exception)
            {
                throw;
            }
            catch (Exception ec)
            {
                LogMgr.Error($"{Name}视觉错误");
                if (null == ec.Source)
                {
                    LogMgr.File($"{Name}视觉错误:{ec.Message}\r\n{ec.StackTrace}");
                }
                else
                {
                    LogMgr.File($"{Name}视觉错误:{ec.Message}\r\n{ec.Source}\r\n{ec.StackTrace}");
                }
                return null;
            }
        }

        public virtual ParamBase LoadParam(string productName)
        {
            return null;
        }

        public async Task<MyPoint> ManualMark(CameraControl view)
        {
            {
                WaitManualMark waitMk = null;
                try
                {
                    await generator.async_call(delegate (Action cb)
                    {
                        waitMk = new WaitManualMark($"开始手动选择 {Name} Mark", cb);
                        waitMk.Show();
                    });
                    waitMk = null;
                }
                finally
                {
                    waitMk?.Close();
                    waitMk = null;
                }
            }
            using (generator.using_lock)
            {
                while (true)
                {
                    view.ShowImage();
                    generator flashDrawMsg = generator.tgo(generator.self_strand(), async delegate ()
                    {
                        while (true)
                        {
                            HOperatorSet.DispText(view.HalconWindow, "左键选择Mark点，右键点击确认", "window", 0, 0, "red", new HTuple("box", "box_color", "shadow"), new HTuple("true", "black", "false"));
                            await generator.sleep(100);
                        }
                    });
                    MyPoint resMark = await generator.send_control(MainForm.obj, delegate ()
                    {
                        return view.DrawPoint();
                    });
                    await generator.stop_other(flashDrawMsg);
                    view.ShowImage();
                    if (0 == resMark.X && 0 == resMark.Y)
                    {
                        await generator.send_control(MainForm.obj, delegate ()
                        {
                            return System.Windows.Forms.MessageBox.Show("没有左键选择Mark点！", $"手动选择 {Name} Mark", System.Windows.Forms.MessageBoxButtons.OK);
                        });
                        continue;
                    }
                    generator flashCross = generator.tgo(generator.self_strand(), async delegate ()
                    {
                        HObject ho_Cross;
                        HOperatorSet.GenCrossContourXld(out ho_Cross, resMark.Row, resMark.Col, 80, 0);
                        while (true)
                        {
                            HOperatorSet.SetColor(view.HalconWindow, "blue");
                            HOperatorSet.DispObj(ho_Cross, view.HalconWindow);
                            await generator.sleep(100);
                        }
                    });
                    try
                    {
                        if (System.Windows.Forms.DialogResult.Yes == await generator.send_control(MainForm.obj, delegate ()
                        {
                            return System.Windows.Forms.MessageBox.Show("确定当前手动选择的Mark点？", $"手动选择 {Name} Mark", System.Windows.Forms.MessageBoxButtons.YesNo);
                        }))
                        {
                            return resMark;
                        }
                    }
                    finally
                    {
                        await generator.stop_other(flashCross);
                    }
                }
            }
        }

        static public string ImagePath
        {
            get
            {
                return DefaultLoad.Load(@"D:\fhs_images", @".\Config\ImagePath.txt", 0);
            }
        }

        static public int ImageDay
        {
            get
            {
                return DefaultLoad.Load(3, @".\Config\ImagePath.txt", 1);
            }
        }

        public void SaveImage(HObject[] ho_Images)
        {
            string currProduct = ProductMgr.currProduct;
            saveWork.service.post(delegate ()
            {
                try
                {
                    string imageRoot = ImagePath;
                    DateTime date = DateTime.Now;
                    string path = $"{imageRoot}/{date.Year}年{date.Month}月{date.Day}日";
                    string SnapPath = $"{path}/{currProduct}/{$"{_productTime.Hour}时{_productTime.Minute}分{_productTime.Second}秒{_productTime.Millisecond}"}/";
                    Directory.CreateDirectory(SnapPath);
                    string name = $"{date.Hour}时{date.Minute}分{date.Second}秒{date.Millisecond}_{Name}_Snap";
                    for (int i = 0; i < ho_Images.Length; i++)
                    {
                        if (null != ho_Images[i])
                        {
                            HOperatorSet.WriteImage(ho_Images[i], "png", 0, $"{SnapPath}/{name}_{i}.png");
                        }
                    }
                }
                catch (Exception) { }
            });
        }

        protected void SaveImage(bool isOk, HObject[] ho_Images)
        {
            string currProduct = ProductMgr.currProduct;
            saveWork.service.post(delegate ()
            {
                try
                {
                    string imageRoot = ImagePath;
                    DateTime date = DateTime.Now;
                    string path = $"{imageRoot}/{date.Year}年{date.Month}月{date.Day}日";
                    string savePath = $"{path}/{currProduct}/{$"{_productTime.Hour}时{_productTime.Minute}分{_productTime.Second}秒{_productTime.Millisecond}"}/";
                    Directory.CreateDirectory(savePath);
                    for (int i = 0; i < ho_Images.Length; i++)
                    {
                        if (null != ho_Images[i])
                        {
                            if (isOk)
                            {
                                string name = $"{date.Hour}时{date.Minute}分{date.Second}秒{date.Millisecond}_{Name}_OK";
                                HOperatorSet.WriteImage(ho_Images[i], "png", 0, $"{savePath}/{name}_{i}.png");
                            }
                            else
                            {
                                string name = $"{date.Hour}时{date.Minute}分{date.Second}秒{date.Millisecond}_{Name}_NG";
                                HOperatorSet.WriteImage(ho_Images[i], "png", 0, $"{savePath}/{name}_{i}.png");
                            }
                        }
                    }
                }
                catch (Exception) { }
            });
        }

        protected void SaveThum(HObject[] ho_Images)
        {
            string currProduct = ProductMgr.currProduct;
            saveWork.service.post(delegate ()
            {
                try
                {
                    string imageRoot = ImagePath;
                    DateTime date = DateTime.Now;
                    string path = $"{imageRoot}/{date.Year}年{date.Month}月{date.Day}日";
                    string thumPath = $"{path}/{currProduct}/{$"{_productTime.Hour}时{_productTime.Minute}分{_productTime.Second}秒{_productTime.Millisecond}"}/";
                    Directory.CreateDirectory(thumPath);
                    string name = $"{date.Hour}时{date.Minute}分{date.Second}秒{date.Millisecond}_{Name}_Thum";
                    for (int i = 0; i < ho_Images.Length; i++)
                    {
                        if (null != ho_Images[i])
                        {
                            try
                            {
                                HObject zoom;
                                HOperatorSet.ZoomImageSize(ho_Images[i], out zoom, 640, 480, "constant");
                                HOperatorSet.WriteImage(zoom, "jpeg", 0, $"{thumPath}/{name}_{i}.jpg");
                            }
                            catch (Exception) { }
                        }
                    }
                }
                catch (Exception) { }
            });
        }

        protected void SaveDump(HWindowControl hWindow)
        {
            string currProduct = ProductMgr.currProduct;
            HObject dumpImage;
            try
            {
                HOperatorSet.DumpWindowImage(out dumpImage, hWindow.HalconWindow);
            }
            catch (Exception)
            {
                return;
            }
            saveWork.service.post(delegate ()
            {
                string imageRoot = ImagePath;
                DateTime date = DateTime.Now;
                string path = $"{imageRoot}/{date.Year}年{date.Month}月{date.Day}日";
                string dumpPath = $"{path}/{currProduct}/{$"{_productTime.Hour}时{_productTime.Minute}分{_productTime.Second}秒{_productTime.Millisecond}"}/";
                try
                {
                    Directory.CreateDirectory(dumpPath);
                    string name = $"{date.Hour}时{date.Minute}分{date.Second}秒{date.Millisecond}_{Name}_Dump";
                    if (null != dumpImage)
                    {
                        try
                        {
                            HOperatorSet.WriteImage(dumpImage, "jpeg", 0, $"{dumpPath}/{name}.jpg");
                        }
                        catch (Exception) { }
                    }
                }
                catch (Exception) { }
            });
        }
    }
}
